﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace RDJTProtocolServer
{
    class Program
    {
        private const string IP = "127.0.0.1";
        private const int Port = 5000;

        static void Main(string[] args)
        {
            var server = new TcpListener(IPAddress.Parse(IP), Port);
            server.Start();

            Console.WriteLine("RDJTP Sever started...");
            // Initialize the main controller, to have it ready for all the clients.
            var controller = new CategoriesController();

            // Wait indefinitely for clients to connect.
            while (true)
            {
                var client = server.AcceptTcpClient();

                var thread = new Thread(
                    () => HandleClient(client, controller)
                );

                thread.Start();
            }
        }

        /**
         * Service a TCP client, read the stream, execute request then close the connection.
         */
        private static void HandleClient(TcpClient client, CategoriesController controller)
        {
            var stream = client.GetStream();

            try
            {
                // Read the message from the client.
                var buffer = new byte[client.ReceiveBufferSize];

                var streamCount = stream.Read(buffer, 0, buffer.Length);
                var message = Encoding.UTF8.GetString(buffer, 0, streamCount);

                // Validate the request format.
                var rdjtp = new Rdjtp(message);
                var success = rdjtp.ValidateRequest();

                // Handle the echo service.
                if (success && rdjtp.Request.Method.Equals("echo"))
                {
                    rdjtp.Response.Body = rdjtp.Request.Body;
                    Console.WriteLine($"Response: {message}");
                }
                // Otherwise handle the request.
                else if (success)
                {
                    controller.HandleRequest(rdjtp.Request, rdjtp.Response);
                }

                // Construct the payload and deliver it.
                var payload = Encoding.UTF8.GetBytes(rdjtp.Response.ToJson());
                stream.Write(payload, 0, payload.Length);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception Occurred: " + e.StackTrace);
            }
            // Close the connection no matter what happened.
            finally
            {
                stream.Close();
                client.Close();
            }
        }
    }
}
